package com.tools.web.work.captcha;

import com.tools.common.object.Note;
import com.tools.common.object.string.StrKit;
import com.tools.common.thread.TimePair;
import com.tools.common.thread.Timeunit;
import com.tools.db.cache.local.EntryHandler;
import com.tools.db.cache.local.LocalCache;

import java.util.Objects;

/**
 * 本地缓存 LocalCache 实现的 CacheService
 * */
@Note("本地缓存 LocalCache 实现的 CacheService。")
public final class LocalCacheCaptchaService extends AbsCaptchaService {

    @Note("本地缓存实例")
    private final LocalCache cache;

    /* ********************************************************************************************
     *
     *          构造器
     *
     * *********************************************************************************************
     * */


    public LocalCacheCaptchaService(LocalCache cache) {
        this.cache = Objects.requireNonNull(cache);
    }

    /* ********************************************************************************************
     *
     *          工具方法
     *
     * *********************************************************************************************
     * */

    public final LocalCache getCache() {
        return cache;
    }

    @Override
    public int checkEqualsCaptcha(String key, String sourceCode, boolean ignoreCase) {
        int[] result = new int[] { 0 };
        EntryHandler handler = new EntryHandler(result, sourceCode, ignoreCase) {
            @Override
            public E handle(Object oldValue, long oldExpirationMill, long oldRefreshMill) throws Exception {
                if(oldValue == null) return null;
                CaptchaResult captcha = (CaptchaResult) oldValue;
                String targetCode = (String) captcha.getCaptcha();
                int[] result = this.getParam(0, int[].class);
                String sourceCode = this.getParam(1, String.class);
                boolean ignoreCase = this.getParam(2, boolean.class);
                if(ignoreCase) {
                    return private_captchaResultHandle(StrKit.equalsIgnoreCase(sourceCode, targetCode),
                            captcha, result, oldValue, oldExpirationMill, oldRefreshMill);
                }
                return private_captchaResultHandle(Objects.equals(sourceCode, targetCode),
                        captcha, result, oldValue, oldExpirationMill, oldRefreshMill);
            }
        };
        this.cache.customHandle(key, handler);
        return result[0];
    }

    @Override
    public int checkEqualsCaptcha(String key, String sourceCode) {
        return this.checkEqualsCaptcha(key, sourceCode, true);
    }


    @Override
    public int checkSlideCaptcha(String key, SlideCaptcha source) {
        int[] result = new int[] { 0 };
        EntryHandler handler = new EntryHandler(result, source) {
            @Override
            public E handle(Object oldValue, long oldExpirationMill, long oldRefreshMill) throws Exception {
                if(oldValue == null) return null;
                CaptchaResult captcha = (CaptchaResult) oldValue;
                SlideCaptcha target = (SlideCaptcha) captcha.getCaptcha();
                int[] result = this.getParam(0, int[].class);
                SlideCaptcha source = this.getParam(1, SlideCaptcha.class);
                return private_captchaResultHandle(Objects.equals(source, target),
                        captcha, result, oldValue, oldExpirationMill, oldRefreshMill);
            }
        };
        this.cache.customHandle(key, handler);
        return result[0];
    }
    
    
    @Override
    public int checkClickCaptcha(String key, ClickCaptcha source) {
        int[] result = new int[] { 0 };
        EntryHandler handler = new EntryHandler(result, source) {
            @Override
            public E handle(Object oldValue, long oldExpirationMill, long oldRefreshMill) throws Exception {
                if(oldValue == null) return null;
                CaptchaResult captcha = (CaptchaResult) oldValue;
                ClickCaptcha target = (ClickCaptcha) captcha.getCaptcha();
                int[] result = this.getParam(0, int[].class);
                ClickCaptcha source = this.getParam(1, ClickCaptcha.class);
                return private_captchaResultHandle(Objects.equals(source, target),
                        captcha, result, oldValue, oldExpirationMill, oldRefreshMill);
            }
        };
        this.cache.customHandle(key, handler);
        return result[0];
    }

    @Override
    public void setEqualsCaptcha(String key, CaptchaResult captchaResult, long expiration, Timeunit timeunit) {
        long expirationMill = Timeunit.toMill(expiration, timeunit);
        this.cache.put(key, captchaResult.asTextIfIs(), expirationMill);
    }

    @Override
    public void setEqualsCaptcha(String key, CaptchaResult captchaResult, TimePair expiration) {
        long expirationMill = expiration.toMill();
        this.cache.put(key, captchaResult.asTextIfIs(), expirationMill);
    }

    @Override
    public void setSlideCaptcha(String key, CaptchaResult captchaResult, long expiration, Timeunit timeunit) {
        long expirationMill = Timeunit.toMill(expiration, timeunit);
        this.cache.put(key, captchaResult, expirationMill);
    }

    @Override
    public void setSlideCaptcha(String key, CaptchaResult captchaResult, TimePair expiration) {
        long expirationMill = expiration.toMill();
        this.cache.put(key, captchaResult, expirationMill);
    }

    @Override
    public void setClickSelectCaptcha(String key, CaptchaResult captchaResult, long expiration, Timeunit timeunit) {
        long expirationMill = Timeunit.toMill(expiration, timeunit);
        this.cache.put(key, captchaResult, expirationMill);
    }

    @Override
    public void setClickSelectCaptcha(String key, CaptchaResult captchaResult, TimePair expiration) {
        long expirationMill = expiration.toMill();
        this.cache.put(key, captchaResult, expirationMill);
    }

    @Override
    public CaptchaResult getEqualsCaptcha(String key) {
        return this.cache.get(key, CaptchaResult.class);
    }

    @Override
    public CaptchaResult getSlideCaptcha(String key) {
        return this.cache.get(key, CaptchaResult.class);
    }

    @Override
    public CaptchaResult getClickSelectCaptcha(String key) {
        return this.cache.get(key, CaptchaResult.class);
    }

    @Override
    public void removeCaptcha(String key) {
        this.cache.remove(key);
    }

    /* ********************************************************************************************
     *
     *          私有逻辑
     *
     * *********************************************************************************************
     * */


    @Note("根据校验结果和是否开启限制次数来决定返回的结果值")
    private static EntryHandler.E private_captchaResultHandle(boolean checkResult,
                                                              CaptchaResult captcha, int[] result,
                                                              Object oldValue, long oldExpirationMill,
                                                              long oldRefreshMill) {
        if(checkResult) {
            result[0] = 1;
            return null;
        }
        if(captcha.enabledLimitCount()) {
            captcha.incrIncorrect();
            if(captcha.reachedThreshold()) {
                result[0] = -2;
            } else {
                result[0] = -1;
            }
        }
        return new EntryHandler.E(oldValue, oldExpirationMill, oldRefreshMill);
    }
}
